北邮操作系统实验三文件系统和设备管理LJ.docx

您所在的位置:网站首页 linux 设备管理 北邮操作系统实验三文件系统和设备管理LJ.docx

北邮操作系统实验三文件系统和设备管理LJ.docx

2023-03-14 09:35| 来源: 网络整理| 查看: 265

北邮操作系统实验三文件系统和设备管理LJ.docx

《北邮操作系统实验三文件系统和设备管理LJ.docx》由会员分享,可在线阅读,更多相关《北邮操作系统实验三文件系统和设备管理LJ.docx(12页珍藏版)》请在冰豆网上搜索。

北邮操作系统实验三文件系统和设备管理LJ.docx

北邮操作系统实验三文件系统和设备管理LJ

操作系统

实验三文件系统和设备管理

作者:

北邮

班级

2009211309

学院(系):

计算机学院

专业:

指导教师:

分数:

目录

1.实验目的2

2.实验要求2

3.具体实现2

3.1.LINUX下串口的非阻塞读写程序……2

3.2.模块……3

3.3实现一个procfs文件系统的模块…………………………7

4.实验心得……………………………………………………………

5.附录源代码9

1.

实验目的

了解LINUX下文件系统和I/O的实现,了解其中模块的设计。

 

2.项目要求

(a)实现一个LINUX下串口的非阻塞读写程序。

(b)了解LINUX下模块的实现方式,及相应的编译和安装及卸载过程。

实现一个模块,在模块安装时可打印信息(Hello)和卸载时打印信息(Goodbye).

(c)实现一个procfs文件系统的模块。

 

3.具体实现

3.1LINUX下串口的非阻塞读写程序

在Linux下串口文件是位于/dev下,串口一为/dev/ttyS0,串口二为/dev/ttyS1打开串口是通过使用标准的文件打开函数操作:

intfd;

/*以读写方式打开串口*/

fd=open("/dev/ttyS0",O_RDWR);

if(-1==fd){

/*不能打开串口一*/

perror("提示错误!

");

}

在使用时还应当设置串口、读写串口、关闭串口等,通过查阅资料实现了对串口的读写

代码见附录

3.2模块

 模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。

它在运行时被链接到内核作为内核的一部分在内核空间运行,这与运行在用户空间的进程是不同的。

模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。

首先在电脑里编写一段C语言代码,hello.c。

代码如下

分析:

(1)在内核模块的开始一部分,跟C语言的一般程序一样,是模块所需要的头文件。

(2)模块许可证声明,这部分是必须有的。

模块许可证(LICENSE)声明描述内核模块的许可权限,如果不声明LICENSE,模块被加载时,将收到内核被污染(kerneltainted)的警告。

大多数情况下,内核模块应遵守GPL兼容许可权。

Linux2.6内核模块最常见的是以MODULE_LICENSE("DualBSD/GPL")语句声明模块采用BSD/GPL双LICENSE。

(3)模块加载函数,这部分是必须的。

模块加载函数必须“module_init(函数名)“的形式被指定。

它返回整形值,若初始化成功,应返回0。

在上面那个例子当中,hello_init()函数就是模块加载函数需要执行的,主要是打印一条信息。

(4)跟模块加载函数相对应的就是模块卸载函数,这部分也是必须的。

模块卸载函数在模块卸载的时候执行,不返回任何值,必须以“module_exit(函数名)“的形式来指定。

在上面的例子中,hello_exit()函数就是模块卸载函数需要执行的,只要是打印了一条退出信息。

(5)函数最后的一部分,是模块声明与描述部分。

这部分可有可无。

在Linux内核模块中,我们可以用

MODULE_AUTHOR,MODULE_DESCRIPTION,MODULE_VERSION,MODULE_DEVICE_TABLE,MODULE_ALIAS分别声明模块的作者、描述、版本、设备表和别名。

(6)module_init()是驱动程序初始化的入口点。

它就相当于c语言程序中的main()函数。

对于内置的模块,内核在引导时调用该引导点,对于可加载模块则在模块插入到内核时才调用。

(7)模块加载函数和模块卸载函数中都用到了printk()函数,该函数是由内核定义的,功能与C库中的printf()类似,它把要打印的信息输出到终端或系统日志中。

 

其次,编写Makefile文件,通过它来管理一个庞大的项目是再好不过的。

下面我们就在刚才.c文件目录下编写一个Makefile文件。

对应的代码如下:

pwd是获得当前的相对路径,然后就是获得当前的内核版本号,我们可以用uname-r命令,这样我们就获得了当前内核的绝对路径。

这样做的一个好处,就是你可以在不同的内核版本中进行移植,而且可读性也增强了。

有了Makefile文件后,就离成功不远了。

在.c文件的同一目录下,执行make命令,系统会在当前目录下生成各种文件。

其中就有与之相关的.o和.ko文件。

hello.ko就是模块目标文件。

到此,模块编译好了。

截图如下:

 

模块编译好了,但是还不能为我们工作。

下面就是将目标模块插入到内核和从内核中删除。

这里需要用到两个命令,insmod和rmmod我们光看这两个命令单词就能猜出他们的意思。

输入命令:

sudoinsmodhello.ko。

要看信息必须要进入到日志文件中,可输入命令进到系统日志:

dmesg,会发现有一条信息,HelloWorld,说明我们刚才编写的模块已经插入到内核当中了。

接下来输入命令:

sudormmodhello.ko。

再输入命令打开系统日志,我们会发现在会有一个新的信息Goodbye,这说明我们的模块卸载成功。

至此,实现一个模块,在模块安装时可打印信息(Helloworld)和卸载时打印信息(Goodbye)完成

3.3实现一个procfs文件系统的模块

/proc文件系统是在LINUX系统中的一个特殊部分,它并不属于任何应用的文件系统,它的主要作用是用于用户与系统的参数交换,但使用更多的是通过/proc系统中的文件内容来查看系统当前运行状态。

程序中主要是要靠调用LINUX提供的系统函数来创建表项和文件夹,并且通过修改读写函数的指针,可以实现对于该文件读写的重调用。

其中,建立文件和文件夹的函数是:

staticstructproc_dir_entry*mydir;

staticstructproc_dir_entry*pfile;

staticintmyproc_write(structfile*,constchar__user*,

unsignedlong,void*)

staticintmyproc_read(char*,char**,off_t,

int,int*,void*)

编写Makefile文件,和上面的类似,这里就不过多赘述。

编写编译procfc_模块,:

生成如下文件:

在/procfc_os中创建mydir文件夹

 

4实验心得

(a)在实验中初步学习了LINUX串口编程,了解了各个函数的功能。

因为硬件的关系,故只是模拟了串口的写入及读出。

实际中应该将两个串口相连来实现

(b)本次实验中亲自动手实践了LINUX内核的模块编程,并初步了解了内核模块在LINUX内核中的位置和运行方式。

加强了对linux模块的了解

(c)本次实验中结合内核模块的编程方式,通过上网查找资料及去图书馆借阅书籍,学会写PROC文件系统的文件。

5附录(3.1及3.3的原程序)

5.1

#include

#include

#include

#include

#include

intmain()

{

intfd,flag,wr_num=0,rd_num=0;

charsend_buf[512],recv_buf[512];

while

(1)

{

fd=open("/dev/minttyS0",O_RDWR|O_NOCTTY|O_NDELAY);

if(fd==-1)

printf("cannotopentheCOM1!

\n");

else

{

fcntl(fd,F_SETFL,0);

printf("openInput-serialportsuccessfully!

\n");

printf("Input:

\n");

scanf("%s",send_buf);

wr_num=write(fd,send_buf,sizeof(send_buf));/*先写入*/

if(wr_num>0)

printf("writesuccess!

\n\n");

else

printf("writefail!

\n\n");

sleep

(1);

}

close(fd);

fd=open("/dev/minttyS0",O_RDWR|O_NOCTTY|O_NDELAY);

if(fd==-1)

printf("cannotopentheCOM2!

\n");

else

{

fcntl(fd,F_SETFL,0);

printf("openOutput-serialportsuccessfully!

\n");

rd_num=read(fd,recv_buf,sizeof(recv_buf));/*再读出*/

if(rd_num>0)

{

recv_buf[rd_num]='\0';

printf("wecanread\"%s\"fromtheCOM1.total:

%dcharacters\n\n",recv_buf,rd_num);

}

else

printf("readfail!

\n");

sleep

(2);

}

close(fd);

}

}

5.2

#include

#include

#include

staticstructproc_dir_entry*mydir;

staticstructproc_dir_entry*pfile;

staticcharmsg[255];

staticintmyproc_read(char*page,char**start,off_toff,intcount,int*eof,void*data)

{

intlen=strlen(msg);

if(off>=len)

return0;

if(count>len-off)

count=len-off;

memcpy(page+off,msg+off,count);

returnoff+count;

}

staticintmyproc_write(structfile*file,constchar__user*buffer,unsignedlongcount,void*data)

{

unsignedlongcount2=count;

if(count2>=sizeof(msg))

count2=sizeof(msg)-1;

if(copy_from_user(msg,buffer,count2))

return-EFAULT;

msg[count2]='\0';

returncount;

}

staticint__initmyproc_init(void)

{

mydir=proc_mkdir("mydir",NULL);

if(!

mydir){

printk(KERN_ERR"Can'tcreate/procfc_os/mydir\n");

return-1;

}

pfile=create_proc_entry("Pool",0666,mydir);

if(!

pfile){

printk(KERN_ERR"Can'tcreate/procfc_os/mydir/pool\n");

remove_proc_entry("mydir",NULL);

return-1;

}

pfile->read_proc=myproc_read;

pfile->write_proc=myproc_write;

return0;

}

staticvoid__exitmyproc_exit(void)

{

remove_proc_entry("pool",mydir);

remove_proc_entry("mydir",NULL);

}

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3